/**
* @program: Go
*
* @description:初始化数据库
*
* @author: Mr.chen
*
* @create: 2020-10-20 14:33
**/
package conn
import (
	cfg "ydd-im/config"
	"ydd-im/util/logger"
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
	"log"
	"math/rand"
	"os"
	"sync"
	"time"
)
var (
	dbUser 	string
	dbPwd 	string
	dbHost 	string
	dbPort 	int64
	dbName  string
)
var dbConn map[string][]*sqlx.DB = make(map[string][]*sqlx.DB)

var syncLock sync.Mutex
//调用方式
//InitDb() 或 InitDb("w") 或 InitDb("default") //初始化主库
//InitDb("w","r")	//同时初始化主库和从库
//InitDb("w")
// 初始化数据库
func InitDb(aliases ...string) {

	//如果是开发模式，则显示命令信息
	if len(aliases) > 0 {
		for _, alias := range aliases {
			registDatabase(alias)
		}
	} else { // 注册主库
		registDatabase("w")
	}
}
// 注册数据库
func registDatabase(alias string) {
	if len(alias) == 0 {
		return
	}
	//连接名称
	if "w" == alias || "default" == alias {
		alias = "w"
	}
	CommonDb :=cfg.GetDbProxyConfig()
	Dbconfig := CommonDb.DbproxyDbconfig[alias]

	if len(Dbconfig) == 0{
		panic("数据库参数无效，请修改数据库配置")
	}
	for k,_ := range Dbconfig { // v是复制值，修改参数无效，建议用Dbconfig[i]
		//数据库连接用户名
		dbUser =  Dbconfig[k].User
		//数据库连接密码
		dbPwd =   Dbconfig[k].PassWd
		//数据库IP（域名）
		dbHost =  Dbconfig[k].Host
		//数据库端口
		dbPort =  Dbconfig[k].Port
		//数据库名
		dbName =  Dbconfig[k].Db
		//数据库连接用户名
		MySQLSource:=fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=true&loc=Local",dbUser,dbPwd,dbHost,dbPort,dbName)
		db, _ := sqlx.Connect("mysql", MySQLSource)
		db.SetConnMaxLifetime(time.Duration(Dbconfig[k].ConnMaxLifetime)*time.Second)
		db.SetMaxOpenConns( Dbconfig[k].MaxOpenConnections)
		db.SetMaxIdleConns( Dbconfig[k].MaxIdleConnections)
		err := db.Ping()
		if err != nil {
			logger.GetLg().Fatal("Failed to connect to mysql, err:" + err.Error())
			os.Exit(1)
		}
		syncLock.Lock()
		dbConn[alias] = append(dbConn[alias],db)
		syncLock.Unlock()

		logger.GetLg().Info("初始化数据库成功，数据库别名："+alias)
	}

}
// DBConn : 返回数据库连接对象
func DBConn(aliases ...string)  (db *sqlx.DB,err error){

	if len(aliases) > 0 {
		for _, alias := range aliases {
			if len(alias) == 0 { // 防止传空值
				alias = "w"
			}
			dbs,ok := dbConn[alias]
			if ok {
				num := rand.Intn(len(dbConn[alias]))
				db =  dbs[num]
				break;
			}else{
				//os.Exit(1)
				logger.GetLg().Warn("数据库连接失败，数据库别名："+alias)
				db =  nil
				break;
			}
		}
	} else { // 注册主库
		dbs,ok := dbConn["w"]
		if ok {
			num := rand.Intn(len(dbConn["w"]))
			db =  dbs[num]
		}else{
			logger.GetLg().Warn("数据库连接失败，数据库别名：w")
			//os.Exit(1)
			db =  nil
		}
	}
	if db == nil {
		return nil,errors.New("数据库连接失败")
	}
	return db,nil
}
// 根据数据库返回对应的行
func ParseRows(rows *sql.Rows) []map[string]interface{} {
	columns, _ := rows.Columns()
	scanArgs := make([]interface{}, len(columns))
	values := make([]interface{}, len(columns))
	for j := range values {
		scanArgs[j] = &values[j]
	}

	record := make(map[string]interface{})
	records := make([]map[string]interface{}, 0)
	for rows.Next() {
		//将行数据保存到record字典
		err := rows.Scan(scanArgs...)
		checkErr(err)
		for i, col := range values {
			if col != nil {
				record[columns[i]] = col
			}
		}
		records = append(records, record)
	}
	return records
}
// 检查错误
func checkErr(err error) {
	if err != nil {
		log.Fatal(err)
		panic(err)
	}
}
